﻿using System;
using Outlook = Microsoft.Office.Interop.Outlook;
using Core = Microsoft.Office.Core;
using MenuItem = OMC.DataManagement.ResultItem;
using Manager = OMC.DataManagement.Manager;
using StringResources = OMC.Properties.StringResources;
using MyForm = OMC.UserInterface.MyForm;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Resources;
using System.Runtime.InteropServices;
using System.Diagnostics;
using OMC.DataManagement;

namespace OMC.AddInHandling
{
    /// <summary>
    /// This class could manage all the things
    /// which are responsable of outlook actions.
    /// </summary>
    class AddInHandler : IDisposable
    {
        private Outlook.Stores stores;
        private Manager manager { get; set; }
        private String TheTextOfTheContextPopupMenu;
        private String TheTextOfContextMenuRefreshButton;
        private String TheTextofMailNotMoved;
        private String TheTextOfContextMenuSaveButton;
        private String TheTextOfSaveFileDialogFilter;
        private String TheTextOfSaveFileDialogTitle;
        private String TheTextOfContextMenuOptions;
        private Core.CommandBarPopup popUpMenu;
        private Core.CommandBarButton button;
        private MyForm userInterfaceOptions;

        /// <summary>
        /// The constructor to create an object of this class.
        /// </summary>
        /// <param name="stores">Outlook stores</param>
        /// <param name="manager">a manager object of class DataManagement.Manager</param>
        public AddInHandler(Outlook.Stores stores, DataManagement.Manager manager)
        {
            this.stores = stores;
            this.manager = manager;
            this.Init();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // free managed resources
                if (userInterfaceOptions != null)
                {
                    userInterfaceOptions.Dispose();
                    userInterfaceOptions = null;
                }
            }
        }

        /// <summary>
        /// This method inits standard resources and default folders.
        /// </summary>
        private void Init()
        {
            try
            {
                this.LoadResources();
                Utils.Debug.Log("Add In handler init");
            }
            catch (Exception ex)
            {
                String message = "It isn't possible to init the Handler";
                Utils.Debug.Log(message, ex, TraceEventType.Critical);
            }
        }

        /// <summary>
        /// This method loads the string resources of the text, which is shown in the user interface.
        /// There are language files based on the culture info. default file is "en"!
        /// </summary>
        /// <example>
        /// The cultureinfo convention, see:
        /// Source:http://msdn.microsoft.com/de-de/library/system.globalization.cultureinfo%28v=vs.80%29.aspx
        /// </example>
        private void LoadResources()
        {
            try
            {
                ResourceManager rm = StringResources.ResourceManager;
                //ContextMenu Strings
                TheTextOfTheContextPopupMenu = rm.GetString("ContextMenuPopupName");
                TheTextOfContextMenuRefreshButton = rm.GetString("ContextMenuRefresh");
                TheTextOfContextMenuOptions = rm.GetString("ContextMenuOption");
                TheTextOfContextMenuSaveButton = rm.GetString("ContextMenuSave");
                //SaveDialog Strigs
                TheTextOfSaveFileDialogFilter = rm.GetString("saveFileDialogFilter");
                TheTextOfSaveFileDialogTitle = rm.GetString("saveFileDialogTitle");
                //UserInfo Strings
                TheTextofMailNotMoved = rm.GetString("MailNotMoved");
            }
            catch (Exception ex)
            {
                String message = "It isn't possible to load Resources!";
                Utils.Debug.Log(message, ex, TraceEventType.Critical);
            }
        }

        /// <summary>
        /// This method moves mails from a folder to another folder.
        /// </summary>
        /// <param name="mailItem">the MailItem, which should be moved</param>
        /// <param name="folderName">the destination folder of the MailItem</param>
        /// <param name="folderExtra">extra info of the folder, like the entryID</param>
        public void MoveMailItem(Outlook.MailItem mailItem, String folderName, String folderExtra)
        {
            foreach (Outlook.Store store in stores)
            {
                try
                {
                    Outlook.Folder root = store.GetRootFolder() as Outlook.Folder;
                    SearchFolderAndMove(root, folderName, mailItem, folderExtra);
                }
                catch (COMException ex)
                {
                    String message = "It isn't possible to search folder in store for moving";
                    Utils.Debug.Log(message, ex, TraceEventType.Error);
                }
            }
        }

        /// <summary>
        /// This method is able to search the folder in the root node and move the mail item to them.
        /// </summary>
        /// <param name="folder">folder, which could contain the possible searched folder</param>
        /// <param name="folderName">the name of the searched folder</param>
        /// <param name="mailItem">the mail item to move</param>
        /// <param name="folderExtra">extra info of the folder, like the entryID</param>
        public void SearchFolderAndMove(Outlook.Folder folder, String folderName,
                                        Outlook.MailItem mailItem, String folderExtra)
        {
            foreach (Outlook.Folder tempFolder in folder.Folders)
            {
                if (tempFolder.Name == folderName && tempFolder.EntryID == folderExtra)
                {
                    try
                    {
                        mailItem.Move(tempFolder);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Mail wurde nicht verschoben");
                        String message = "It isn't possible to move mail to folder";
                        Utils.Debug.Log(message, ex, TraceEventType.Warning);
                    }
                }
                SearchFolderAndMove(tempFolder, folderName, mailItem, folderExtra);
            }
        }

        /// <summary>
        /// This method creates a contextmenu item, which is type of popup menu.
        /// </summary>
        /// <param name="cmdBar">the command bar of the right clicked item</param>
        public void MakeContextPopUp(Core.CommandBar cmdBar)
        {
            try
            {
                //Create PopUpMenu in the ContextMenu
                popUpMenu = cmdBar.Controls.Add(Core.MsoControlType.msoControlPopup,
                                                         Type.Missing,
                                                         Type.Missing,
                                                         Type.Missing, true) as Core.CommandBarPopup;
                popUpMenu.BeginGroup = true;
                popUpMenu.Caption = TheTextOfTheContextPopupMenu;
                popUpMenu.Enabled = false;

                //set PopUpMenu Visible
                popUpMenu.Visible = true;
            }
            catch (COMException ex)
            {
                String message = "It isn't possible to create context popup menu";
                Utils.Debug.Log(message, ex, TraceEventType.Critical);
            }
        }

        /// <summary>
        /// This method handle the right click event of a mail item.
        /// </summary>
        /// <param name="commandBar">this Commandbar could be modified</param>
        /// <param name="selection">this Selection could be use to determine the Mailitem</param>
        public void contextMenuDisplay(Core.CommandBar commandBar, Outlook.Selection selection)
        {
            if (selection != null)
            {
                if (selection.Count == 1)
                {
                    object selectedItem = selection[1];
                    if (selectedItem is Outlook.MailItem)
                    {
                        Outlook.MailItem mailItem = selectedItem as Outlook.MailItem;
                        if (mailItem != null)
                        {
                            //Create context popup menu
                            MakeContextPopUp(commandBar);
                            //load selected Maildata an create a MailContent object
                            MailContent selectedMailItemContent = new MailContent(
                                mailItem.Body, mailItem.Subject, mailItem.SenderEmailAddress, mailItem.To);

                            if (!manager.IsDataSetLoaded())
                            {
                                return;
                            }
                            //Classify selected item
                            List<MenuItem> predictedFolderList = manager.Classify(selectedMailItemContent);

                            //Create the Context Menu
                            MakeContextMenuButtons(commandBar, predictedFolderList, mailItem);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// This Methode could be use to create the Context menu of
        /// each Mailitem with the assoziated Folder, classified by Weka.
        /// </summary>
        /// <example>
        /// Source CommandBar:  http://support.microsoft.com/kb/303018
        /// Source FaceID:      http://www.kebabshopblues.co.uk/2007/01/04/visual-studio-2005-tools-for-office-commandbarbutton-faceid-property/
        /// </example>
        /// <param name="cmdBar">this Commandbar could be modified</param>
        /// <param name="menuItemList">a list, which contains the classified folder names of the selected mail item</param>
        /// <param name="mailItem">the selected mail item</param>
        public void MakeContextMenuButtons(Core.CommandBar cmdBar, List<MenuItem> menuItemList, Outlook.MailItem mailItem)
        {
            try
            {
                foreach (ResultItem menuItem in menuItemList)
                {
                    //Create Buttons to the PopUpMenu
                    button = popUpMenu.Controls.Add(Core.MsoControlType.msoControlButton,
                                                        Type.Missing,
                                                        Type.Missing,
                                                        Type.Missing, true) as Core.CommandBarButton;
                    button.Style = Core.MsoButtonStyle.msoButtonIconAndWrapCaption;
                    button.FaceId = 0133;
                    button.Caption = String.Format("{0} ({1:F1} %)", menuItem.FolderName, menuItem.Probability);

                    //Set delegate to the ClickEventHandler
                    String folderName = menuItem.FolderName;
                    String folderExtra = menuItem.FolderExtraInfo;
                    button.Click += new Core._CommandBarButtonEvents_ClickEventHandler(
                            (Core.CommandBarButton Cmd, ref bool Can) => TheButton_Click(Cmd, ref Can, mailItem, folderName, folderExtra));
                    button.Visible = true;
                }

                //Create Option Buttons to the PopUpMenu
                button = popUpMenu.Controls.Add(Core.MsoControlType.msoControlButton,
                                                    Type.Missing,
                                                    Type.Missing,
                                                    Type.Missing, true) as Core.CommandBarButton;
                button.BeginGroup = true;
                button.Style = Core.MsoButtonStyle.msoButtonIconAndWrapCaption;
                button.FaceId = 0439;
                button.Caption = TheTextOfContextMenuOptions;

                //Set delegate to the ClickEventHandler
                button.Click += new Core._CommandBarButtonEvents_ClickEventHandler(TheOptionsButton_Click);
                button.Visible = true;

                //Set PopUpMenu enabled
                popUpMenu.Enabled = true;
            }
            catch (COMException ex)
            {
                String message = "It isn't possible to create buttons to context menu";
                Utils.Debug.Log(message, ex, TraceEventType.Critical);
            }
        }

        /// <summary>
        /// The method, which is called by a button events handler.
        /// </summary>
        /// <param name="cmdBarButton">the commandbar button, which called this method</param>
        /// <param name="Cancel">cancel</param>
        /// <param name="mailItem">the mail item to move</param>
        /// <param name="folderName">the folder name of the destination folder of the mail item</param>
        /// /// <param name="folderExtra">extra info of the folder, like the entryID</param>
        private void TheButton_Click(Core.CommandBarButton cmdBarButton, ref bool Cancel,
                                     Outlook.MailItem mailItem, String folderName, String folderExtra)
        {
            MoveMailItem(mailItem, folderName, folderExtra);
        }

        /// <summary>
        /// This method opens a form to customize properties.
        /// </summary>
        /// <param name="cmdBarButton">the commandbar button, which called this method</param>
        /// <param name="Cancel">cancel</param>
        private void TheOptionsButton_Click(Core.CommandBarButton cmdBarButton, ref bool Cancel)
        {
            try
            {
                userInterfaceOptions = new MyForm(manager);
                userInterfaceOptions.Show();
            }
            catch (Exception ex)
            {
                String message = "It isn't possible to open Optionsmenu (Form)";
                Utils.Debug.Log(message, ex, TraceEventType.Critical);
            }
        }
    }
}